package cn.woochen.mvvmframe.config.factory

import cn.woochen.mvvmframe.config.convert.CustomGsonRequestBodyConverter
import cn.woochen.mvvmframe.config.convert.CustomizeGsonResponseBodyConverter
import cn.woochen.comlib.http.gson.CollectionTypeAdapterFactory
import cn.woochen.comlib.http.gson.JsonAdapterAnnotationTypeAdapterFactory
import cn.woochen.comlib.http.gson.ReflectiveTypeAdapterFactory
import com.google.gson.*
import com.google.gson.internal.ConstructorConstructor
import com.google.gson.internal.Excluder
import com.google.gson.reflect.TypeToken
import okhttp3.RequestBody
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Field
import java.lang.reflect.Type

/**
 * 自定义Gson转化类
 * @author woochen
 * @time 2019/9/9 10:04
 */
class CustomizeGsonConverterFactory private constructor(private var gson: Gson? = null) :
    Converter.Factory() {

    init {
        if (gson == null) {
            val gsonBulder = GsonBuilder()
            val f: Field = gsonBulder::class.java.getDeclaredField("instanceCreators")
            f.isAccessible = true
            val instanceCreator = f.get(gsonBulder) as Map<Type, InstanceCreator<*>>
            val constructorConstructor = ConstructorConstructor(instanceCreator)
            gson = gsonBulder
                .registerTypeAdapterFactory(ReflectiveTypeAdapterFactory(constructorConstructor, FieldNamingPolicy.IDENTITY, Excluder.DEFAULT, JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor)))
                .registerTypeAdapterFactory(CollectionTypeAdapterFactory(constructorConstructor))
                .registerTypeAdapterFactory(NotNullAdapterFactory())
                .create()
        }
    }

    override fun requestBodyConverter(type: Type?, parameterAnnotations: Array<Annotation>?, methodAnnotations: Array<Annotation>?, retrofit: Retrofit?): Converter<*, RequestBody>? {
        val adapter = gson?.getAdapter(TypeToken.get(type)) as TypeAdapter<*>
        return CustomGsonRequestBodyConverter(gson!!, adapter)
    }

    override fun responseBodyConverter(type: Type?, annotations: Array<Annotation>?, retrofit: Retrofit?): Converter<ResponseBody, *>? {
        val adapter = gson?.getAdapter(TypeToken.get(type)) as TypeAdapter<*>
        return CustomizeGsonResponseBodyConverter(adapter)
    }

    companion object {

        @JvmOverloads
        fun create(): CustomizeGsonConverterFactory {
            return CustomizeGsonConverterFactory()
        }
    }
}
